<!--
 * @Description: 
 * @Author: wuwl
 * @Date: 2024-04-03 21:29:38
 * @FilePath: \web-case-exercise\js\执行上下文\2.变量对象和作用域链.html
 * @LastEditTime: 2024-04-03 21:40:17
 * @LastEditors: wuwl
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 定义执行上下文对象
        class ExecutionContext {
            constructor(name) {
                this.name = name;
                this.variableObject = {}; // 变量对象
                this.scopeChain = []; // 作用域链
                this.thisValue = undefined; // this
            }
        }

        // 定义执行上下文栈
        class ExecutionContextStack {
            constructor() {
                this.stack = [];
            }

            // 推入执行上下文
            push(context) {
                // 更新作用域链
                if (this.stack.length > 0) {
                    context.scopeChain = [...this.stack[this.stack.length - 1].scopeChain, context.variableObject];
                } else {
                    context.scopeChain = [context.variableObject];
                }
                this.stack.push(context);

                console.log('stack', this.stack);
                console.log('context', context);
            }

            // 弹出执行上下文
            pop() {
                console.log('stack', this.stack);
                return this.stack.pop();
            }

            // 获取当前栈顶执行上下文
            peek() {
                return this.stack[this.stack.length - 1];
            }

            // 获取执行上下文栈的大小
            size() {
                return this.stack.length;
            }
        }

        var scope = "global scope"; // 声明一个全局变量 scope，赋值为 "global scope"
        function checkscope() { // 定义函数 checkscope
            var scope = "local scope"; // 声明一个局部变量 scope，赋值为 "local scope"
            function f() { // 定义内部函数 f
                return scope; // 返回当前作用域中的 scope 变量的值
            }
            return f(); // 调用内部函数 f 并返回其结果
        }
        checkscope(); // 调用函数 checkscope

        // 创建全局上下文栈实例
        const ecs = new ExecutionContextStack();

        // 创建全局执行上下文
        const globalContext = new ExecutionContext("global"); // 创建全局执行上下文对象，名称为 "global"
        globalContext.variableObject.scope = "global scope"; // 将全局变量 scope 的值设置为 "global scope"
        ecs.push(globalContext)
        console.log("current context:", ecs.peek().name); // 打印当前执行上下文的名称

        //创建checkScope函数执行上下文。
        const checkScopeContext = new ExecutionContext("checkscope"); // 创建 checkscope 函数执行上下文对象，名称为 "checkscope"
        checkScopeContext.variableObject.scope = undefined; // 在 checkscope 函数执行上下文中，变量对象中的 scope 属性为 undefined
        checkScopeContext.variableObject.arguments = { length: 0 }; // 在 checkscope 函数执行上下文中，变量对象中的 arguments 属性为一个对象，表示没有传入参数

        function checkScope() { // 定义函数 checkScope
            ecs.push(checkScopeContext); // 将 checkScope 函数执行上下文推入执行上下文栈中，表示进入了 checkScope 函数的执行过程
            checkScopeContext.variableObject.scope = "local scope"; // 将局部变量 scope 的值设置为 "local scope"，表示进入了 checkScope 函数内部的执行过程
            var scope = 'local scope'; // 声明一个局部变量 scope，赋值为 "local scope"
            // 创建 f 函数执行上下文
            const fContext = new ExecutionContext("f"); // 创建内部函数 f 的执行上下文对象，名称为 "f"
            fContext.variableObject.scope = undefined; // 在 f 函数执行上下文中，变量对象中的 scope 属性为 undefined
            fContext.variableObject.arguments = { length: 0 }; // 在 f 函数执行上下文中，变量对象中的 arguments 属性为一个对象，表示没有传入参数
            function f() { // 定义内部函数 f
                ecs.push(fContext); // 将 f 函数执行上下文推入执行上下文栈中，表示进入了 f 函数的执行过程
                console.log("current context:", ecs.peek().name); // 打印当前执行上下文的名称
                ecs.pop(); // 弹出栈顶执行上下文，表示退出了 f 函数的执行过程
                return scope; // 返回当前作用域中的 scope 变量的值
            }
            const result = f(); // 调用内部函数 f，并将结果保存在 result 变量中
            ecs.pop(); // 弹出栈顶执行上下文，表示退出了 checkScope 函数的执行过程
            return result; // 返回函数执行结果
        }

        const result = checkScope(); // 调用函数 checkScope，并将结果保存在 result 变量中
    </script>
</body>

</html>